package com.nt.thah.utils;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import org.apache.commons.codec.binary.Base64;

/**
  * @Description： 加密工具类
  * @Author: ls
  * @Date:  2021/4/26 2:30 下午
  */
public class EncryptUtils {

    public final static String ALGO_AES_CBC_NoPadding = "AES/CBC/NoPadding";
    public final static String ALGO_AES_CBC_PKCS5Padding = "AES/CBC/PKCS5Padding";
    public final static String ALGO_AES_ECB_NoPadding = "AES/ECB/NoPadding";
    public final static String ALGO_AES_ECB_PKCS5Padding = "AES/ECB/PKCS5Padding";

    /**
     * @Description： AES加密带偏移量
     * @Author: ls
     * @Date:  2021/4/27 9:27 上午
     */
    public static String encryptWithOffsetByAES(String data, String key) throws Exception {
        //偏移量
        byte[] iv = key.getBytes();
        Cipher cipher = Cipher.getInstance(ALGO_AES_CBC_NoPadding);
        int blockSize = cipher.getBlockSize();
        byte[] dataBytes = data.getBytes();
        int length = dataBytes.length;
        //计算需要填充长度
        if (length % blockSize != 0) {
            length = length + (blockSize - (length % blockSize));
        }
        byte[] plaintext = new byte[length];
        //填充补位数据
        System.arraycopy(dataBytes, 0, plaintext, 0, dataBytes.length);
        SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), "AES");
        //设置偏移量参数
        IvParameterSpec ivSpec = new IvParameterSpec(iv);
        cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
        byte[] encrypt = cipher.doFinal(plaintext);
        return new Base64().encodeToString(encrypt);
    }

    /**
      * @Description： AES解密带偏移量
      * @Author: ls
      * @Date:  2021/4/27 9:27 上午
      */
    public static String decryptWithOffsetByAES(String data, String key) throws Exception {
        //偏移量
        byte[] iv = key.getBytes();
        byte[] encrypted = new Base64().decode(data);
        Cipher cipher = Cipher.getInstance(ALGO_AES_CBC_NoPadding);
        SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), "AES");
        //设置偏移量参数
        IvParameterSpec ivSpec = new IvParameterSpec(iv);
        cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
        byte[] original = cipher.doFinal(encrypted);
        return new String(original);
    }

    /**
     * 业务报文AES加密
     *
     * @param inputStr  业务报文
     * @param randomKey 16位随机数字符串
     * @return
     */
    public static String encryptByAES(String inputStr, String randomKey) throws Exception {
        byte[] inputByte = inputStr.getBytes(StandardCharsets.UTF_8);
        byte[] pwdByte = randomKey.getBytes(StandardCharsets.UTF_8);
        // AES加密
        Cipher cipher = Cipher.getInstance("AES");
        SecretKeySpec secretKeySpec = new SecretKeySpec(pwdByte, "AES");
        cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
        byte[] ret = cipher.doFinal(inputByte);
        return new Base64().encodeToString(ret);
    }

    /**
     * RSA加密16位随机数
     *
     * @param randomKey    16位随机数字符串
     * @param publicKeyStr 服务端公钥
     * @return 加密后的字符串
     */
    public static String encryptByRSA(String randomKey, String publicKeyStr) throws Exception {
        byte[] pkByte = new Base64().decode(publicKeyStr);
        X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(pkByte);
        PublicKey publicKey = KeyFactory.getInstance("RSA").generatePublic(publicKeySpec);
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        byte[] outByte = cipher.doFinal(randomKey.getBytes(StandardCharsets.UTF_8));
        return new Base64().encodeToString(outByte);
    }

    /**
     * AES解密
     *
     * @param inputStr 加密报文字符串
     * @param password 随机数密码
     * @return 解密后的业务报文
     * @throws Exception
     */
    public static String decryptByAES(String inputStr, String password) throws Exception {
        byte[] data = new Base64().decode(inputStr);
        byte[] pwd = password.getBytes(StandardCharsets.UTF_8);
        Cipher cipher = Cipher.getInstance("AES");
        SecretKeySpec keySpec = new SecretKeySpec(pwd, "AES");
        cipher.init(Cipher.DECRYPT_MODE, keySpec);
        byte[] ret = cipher.doFinal(data);
        return new String(ret, StandardCharsets.UTF_8);
    }

    /**
     * 解密
     *
     * @param inputStr   16位随机数加密后的字符串
     * @param privateKey 私钥
     * @return 解密后的16位随机数密码
     * @throws Exception
     */
    public static String decryptByRSA(String inputStr, String privateKey) throws Exception {
        byte[] keyBytes = new Base64().decode(privateKey);
        //取得私钥
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        //生成私钥对象
        PrivateKey pk = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        cipher.init(Cipher.DECRYPT_MODE, pk);
        byte[] output = cipher.doFinal(new Base64().decode(inputStr));
        return new String(output, StandardCharsets.UTF_8);
    }
}
